package multi_thread.advanced.blocking_queue;


import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author Cheng Jun
 * Description: 有锁、有界性(可以有界，也可以无界)、阻塞式的线程安全队列
 * BlockingQueue implementations are designed to be used primarily for producer-consumer queues.
 * 利用 LinkedBlockingQueue 实现 生产者-消费者模式。
 * Linked queues typically have higher throughput than array-based queues
 * but less predictable performance in most concurrent applications.(比基于数组的队列拥有更高的吞吐量，但性能难以预测)
 * The optional capacity bound constructor argument serves as a way to prevent excessive queue expansion.
 * LinkedBlockingQueue 是基于链表实现的阻塞队列，当然满足队列的FIFO，链表实现意味着可以无界，但是为了防止无限扩展，可以设置capacity
 * 内部采用读写分离，读取和写入可同时进行。因为 入列 和 出列 的系列方法各有一把 reentrantLock
 * @version 1.0
 * @date 2021/10/14 20:47
 * @see ArrayBlockingQueueExample
 * 从队列的有界性来说，LinkedBlockingQueue 可以设置容量，也可以不设置容量，有界性可由开发者自行控制；ArrayBlockingQueue 是有界的，不能无界
 * 从队列的并发性来说，LinkedBlockingQueue 读写操作分离，可以同时进行，ArrayBlockingQueue 读写不分离，读写操作不可同时进行。
 * 所以 LinkedBlockingQueue 优于 ArrayBlockingQueue
 * Condition notFull 队列非满状态，意味着可以放元素
 * Condition notEmpty 队列非空状态，意味着可以取元素
 * 生产者/消费者模式
 * 重点掌握
 */
public class LinkedBlockingQueueExample {

    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingQueue<String> linkedBlockingQueue = new LinkedBlockingQueue<>(100);
        Producer producer = new Producer(linkedBlockingQueue);
        // 多消费者模式，当然也可以使用多个生产者
        Consumer consumer0 = new Consumer(linkedBlockingQueue);
        Consumer consumer1 = new Consumer(linkedBlockingQueue);
        new Thread(producer).start();
        new Thread(consumer0).start();
        new Thread(consumer1).start();
    }
}

class Producer implements Runnable {
    private LinkedBlockingQueue<String> blockingQueue;

    public Producer(LinkedBlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
                blockingQueue.put(produce());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 随机生成一个 小写字母
     *
     * @return
     */
    private String produce() {
        Random random = new Random();
        return String.valueOf((char) (random.nextInt(26) + 'a'));
    }

}

class Consumer implements Runnable {
    private LinkedBlockingQueue<String> blockingQueue;

    public Consumer(LinkedBlockingQueue<String> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                consume(blockingQueue.take());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void consume(String element) {
        System.out.println(Thread.currentThread().getName() + " " + element + "转化成大写" + element.toUpperCase());
    }
}